package com.plm.k8s.myk8sapi.cmd.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.plm.k8s.myk8sapi.cmd.AbstractLocalCmd;
import com.plm.k8s.myk8sapi.cmd.IStsCmd;
import com.plm.k8s.myk8sapi.pojo.entity.pod.*;
import com.plm.k8s.myk8sapi.pojo.entity.sts.*;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.File;
import java.util.*;

/**
 * @author 潘磊明
 * 版本号：1.0
 * 创建日期：2021/7/28 17:10
 */
@Service
public class StsCmdImpl extends AbstractLocalCmd implements IStsCmd {

    @Override
    public List<StsEntity> listSts(boolean isAll, String namespace, String nameFilter, Map<String, String> labelFilter) throws Exception {
        String cmd = generateListStsCmd(isAll, namespace, nameFilter, labelFilter);
        ApiStsEntity apiStsEntity = execForYamlObject(cmd, ApiStsEntity.class);
        if (apiStsEntity == null) return Collections.emptyList();
        return apiStsEntity.getItems();
    }

    @Override
    public boolean createSts(File file) throws Exception {
        String result = applyYamlFile(file);
        if (!result.contains("created")) {
            throw new Exception(result);
        }
        return true;
    }

    @Override
    public boolean createSts(String name, String image, String serviceName, Integer replicas, String imagePullPolicy, List<PodSpecContainerEnvEntity> envs,
            List<PodSpecContainerPortEntity> ports, List<PodSpecContainerVolumeMountEntity> volumeMounts,
            List<StsSpecVolumeClaimTemplateEntity> volumeClaimTemplates, String namespace, Integer terminationGracePeriodSeconds,
            List<String> command, PodSpecContainerStartupProbeEntity startupProbe, PodSpecContainerLivenessProbeEntity livenessProbe,
            PodSpecContainerReadinessProbeEntity readinessProbe, PodSpecContainerLifecycleEntity lifecycle) throws Exception {
        if (!StringUtils.hasText(name)) throw new Exception("StatefulSet的名称不能为空");
        if (!StringUtils.hasText(image)) throw new Exception("StatefulSet的镜像不能为空");
        if (!StringUtils.hasText(serviceName)) throw new Exception("StatefulSet的服务名不能为空");
        StsEntity stsEntity = generateBaseSts(name, serviceName, replicas, namespace);
        setMoreInfo(stsEntity, name, image, imagePullPolicy, envs, ports, volumeMounts, terminationGracePeriodSeconds, command,
                startupProbe, livenessProbe, readinessProbe, lifecycle, volumeClaimTemplates);
        File stsFile = transferObject2YamlFile(stsEntity);
        return createSts(stsFile);
    }

    @Override
    public boolean deleteSts(String name, String namespace) throws Exception {
        String cmd = generateDeleteStsCmd(name, namespace);
        String result = exec(cmd);
        if (!String.format("statefulset.apps \"%s\" deleted", name).equals(trimBr(result))) {
            throw new Exception(result);
        }
        return true;
    }

    @Override
    public boolean scaleSts(String name, Integer replicas, String namespace) throws Exception {
        if (!StringUtils.hasText(name)) throw new Exception("StatefulSet的名称不能为空");
        if (replicas == null) throw new Exception("StatefulSet的副本数不能为空");
        String cmd = generateScaleStsCmd(name, replicas, namespace);
        String result = exec(cmd);
        if (!String.format("statefulset.apps/%s scaled", name).equals(trimBr(result))) {
            throw new Exception(result);
        }
        return true;
    }

    private String generateScaleStsCmd(String name, Integer replicas, String namespace) {
        StringBuilder sb = new StringBuilder(generateKubeCmdBase());
        sb.append("scale ").append("--replicas=").append(replicas).append(" statefulset/").append(name);
        if (StringUtils.hasText(namespace)) sb.append(" -n ").append(namespace);
        return sb.toString();
    }

    private String generateDeleteStsCmd(String name, String namespace) {
        StringBuilder sb = new StringBuilder(generateKubeCmdBase());
        sb.append("delete sts ").append(name);
        if (StringUtils.hasText(namespace)) sb.append(" -n ").append(namespace);
        return sb.toString();
    }

    private void setMoreInfo(StsEntity stsEntity, String name, String image, String imagePullPolicy,
            List<PodSpecContainerEnvEntity> envs, List<PodSpecContainerPortEntity> ports,
            List<PodSpecContainerVolumeMountEntity> volumeMounts, Integer terminationGracePeriodSeconds,
            List<String> command, PodSpecContainerStartupProbeEntity startupProbe, PodSpecContainerLivenessProbeEntity livenessProbe,
            PodSpecContainerReadinessProbeEntity readinessProbe, PodSpecContainerLifecycleEntity lifecycle, List<StsSpecVolumeClaimTemplateEntity> volumeClaimTemplates) {
        StsSpecTemplateEntity specTemplateEntity = stsEntity.getSpec().getTemplate();
        StsSpecTemplateSpecEntity stsSpecTemplateSpecEntity = specTemplateEntity.getSpec();
        PodSpecContainerEntity containerEntity = new PodSpecContainerEntity();
        containerEntity.setName(name);
        containerEntity.setImage(image);
        if (StringUtils.hasText(imagePullPolicy)) containerEntity.setImagePullPolicy(imagePullPolicy);
        if (CollectionUtil.isNotEmpty(envs)) containerEntity.setEnv(envs);
        if (CollectionUtil.isNotEmpty(ports)) containerEntity.setPorts(ports);
        if (CollectionUtil.isNotEmpty(volumeMounts)) containerEntity.setVolumeMounts(volumeMounts);
        if (terminationGracePeriodSeconds != null) stsSpecTemplateSpecEntity.setTerminationGracePeriodSeconds(terminationGracePeriodSeconds);
        if (CollectionUtil.isNotEmpty(command)) containerEntity.setCommand(command);
        if (startupProbe != null) containerEntity.setStartupProbe(startupProbe);
        if (livenessProbe != null) containerEntity.setLivenessProbe(livenessProbe);
        if (readinessProbe != null) containerEntity.setReadinessProbe(readinessProbe);
        if (lifecycle != null) containerEntity.setLifecycle(lifecycle);
        stsSpecTemplateSpecEntity.getContainers().add(containerEntity);
        if (CollectionUtil.isNotEmpty(volumeClaimTemplates)) stsEntity.getSpec().setVolumeClaimTemplates(volumeClaimTemplates);
    }

    private StsEntity generateBaseSts(String name, String serviceName, Integer replicas, String namespace) {
        StsEntity stsEntity = new StsEntity();
        stsEntity.setApiVersion("apps/v1");
        stsEntity.setKind("StatefulSet");

        /******************元数据信息********************/
        StsMetadataEntity metadataEntity = new StsMetadataEntity();
        metadataEntity.setName(name);
        if (StringUtils.hasText(namespace)) metadataEntity.setNamespace(namespace);
        stsEntity.setMetadata(metadataEntity);

        /*******************规格信息*************************/
        StsSpecEntity specEntity = new StsSpecEntity();
        specEntity.setServiceName(serviceName);
        specEntity.setReplicas(replicas);
        StsSpecSelectorEntity specSelectorEntity = new StsSpecSelectorEntity();
        Map<String, String> matchLabels = new LinkedHashMap<>();
        matchLabels.put("app", name);
        specSelectorEntity.setMatchLabels(matchLabels);
        specEntity.setSelector(specSelectorEntity);

        /********************模板信息**************************/
        StsSpecTemplateEntity stsSpecTemplateEntity = new StsSpecTemplateEntity();
        StsSpecTemplateMetadataEntity stsSpecTemplateMetadataEntity = new StsSpecTemplateMetadataEntity();
        Map<String, String> labels = new LinkedHashMap<>();
        labels.put("app", name);
        stsSpecTemplateMetadataEntity.setLabels(labels);
        stsSpecTemplateEntity.setMetadata(stsSpecTemplateMetadataEntity);
        StsSpecTemplateSpecEntity stsSpecTemplateSpecEntity = new StsSpecTemplateSpecEntity();
        stsSpecTemplateSpecEntity.setContainers(new LinkedList<>());
        stsSpecTemplateEntity.setSpec(stsSpecTemplateSpecEntity);
        specEntity.setTemplate(stsSpecTemplateEntity);
        stsEntity.setSpec(specEntity);

        return stsEntity;
    }

    private String generateListStsCmd(boolean isAll, String namespace, String nameFilter, Map<String, String> labelFilter) {
        StringBuilder sb = new StringBuilder(generateKubeCmdBase());
        sb.append("get sts -o yaml");
        if (isAll) {
            sb.append(CMD_DELIMITER).append("-A");
        } else {
            if (StringUtils.hasText(namespace)) addNamespace(sb, namespace);
        }
        if (StringUtils.hasText(nameFilter)) addNameFilter(sb, nameFilter);
        if (CollectionUtil.isNotEmpty(labelFilter)) addLabelFilter(sb, labelFilter);
        return sb.toString();
    }
}
